package com.hello.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hello.sky.constant.MessageConstant;
import com.hello.sky.constant.StatusConstant;
import com.hello.sky.exception.SkyException;
import com.hello.sky.mapper.*;
import com.hello.sky.model.dto.DishDTO;
import com.hello.sky.model.dto.DishPageQueryDTO;
import com.hello.sky.model.entity.Category;
import com.hello.sky.model.entity.Dish;
import com.hello.sky.model.entity.DishFlavor;
import com.hello.sky.model.entity.SetmealDish;
import com.hello.sky.model.vo.DishVO;
import com.hello.sky.result.PageResult;
import com.hello.sky.service.DishService;
import com.hello.sky.util.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜品 服务实现类
 * </p>
 *
 * @author D
 */
@Slf4j
@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {

    @Autowired
    private DishFlavorMapper dishFlavorMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;
    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Transactional
    @Override
    public void addDish(DishDTO dishDTO) {
        //- 菜品名称必须是唯一的
        //- 菜品必须属于某个分类下，不能单独存在
        if (dishDTO.getCategoryId() == null) throw SkyException.cast("菜品必须要有分类");
        //- 新增菜品时可以根据情况选择菜品的口味
        //- 每个菜品必须对应一张图片
        if (dishDTO.getImage() == null) throw SkyException.cast("菜品必须要有图片");

        //菜品表
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);
        this.baseMapper.addDish(dish);
        Long id = dish.getId();
        //口味表
        List<DishFlavor> flavors = dishDTO.getFlavors();
        if (flavors.size() > 0) dishFlavorMapper.addFlavor(flavors, id);

        //删除缓存
        delCache("category_" + dish.getCategoryId());
    }

    @Override
    public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
        LambdaQueryWrapper<Dish> dishQr = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(dishPageQueryDTO.getName())) dishQr.like(Dish::getName, dishPageQueryDTO.getName());
        if (dishPageQueryDTO.getCategoryId() != null) dishQr.eq(Dish::getCategoryId, dishPageQueryDTO.getCategoryId());
        if (dishPageQueryDTO.getStatus() != null) dishQr.eq(Dish::getStatus, dishPageQueryDTO.getStatus());
        dishQr.orderBy(true, false, Dish::getUpdateTime);
        Page<Dish> page = page(new Page<>(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize()), dishQr);

        List<Category> categories = categoryMapper.selectList(null);
        Map<Long, String> map = categories.stream().collect(Collectors.toMap(Category::getId, Category::getName));
        List<DishVO> records = page.getRecords().stream().map(dish -> {
            DishVO dishVO = new DishVO();
            BeanUtils.copyProperties(dish, dishVO);
            String categoryName = map.get(dish.getCategoryId());
            dishVO.setCategoryName(categoryName);
            return dishVO;
        }).collect(Collectors.toList());

        return new PageResult(page.getTotal(), records);
    }

    @Transactional
    @Override
    public void deleteDishes(List<Long> ids) {
        //是否在售
        for (Long id : ids) {
            Dish dish = this.baseMapper.selectById(id);
            if (dish.getStatus() == StatusConstant.ENABLE) throw SkyException.cast("在售商品不允许删除");
        }
        //是否有套餐
        List<Long> seatMealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);
        if (seatMealIds != null && seatMealIds.size() > 0) throw SkyException.cast("已关联菜品，禁止删除");
        //删除菜品和口味
        this.baseMapper.delByIds(ids);
        dishFlavorMapper.delByDishIds(ids);

        //删除缓存
        delCache("category_*");
    }

    @Override
    public DishVO getDishById(Long id) {
        //查菜品
        Dish dish = baseMapper.selectById(id);
        //查该菜品的口味
        List<DishFlavor> flavorList = dishFlavorMapper.getFlavorByDishId(id);
        //封装vo
        DishVO dishVO = new DishVO();
        BeanUtils.copyProperties(dish, dishVO);
        dishVO.setFlavors(flavorList);
        return dishVO;
    }

    @Transactional
    @Override
    public void updateDishWithFlavor(DishDTO dishDTO) {
        //更新dish
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);
        baseMapper.updateDishById(dish);

        //删除原有的口味数据
        dishFlavorMapper.deleteByDishId(dishDTO.getId());
        //重新插入口味数据
        List<DishFlavor> flavors = dishDTO.getFlavors();
        if (flavors != null && flavors.size() > 0) {
            flavors.forEach(dishFlavor -> {
                dishFlavor.setDishId(dishDTO.getId());
            });
            //向口味表插入n条数据
            dishFlavorMapper.addFlavorBatch(flavors);
        }

        //删除缓存
        delCache("category_*");
    }

    @Override
    public List<DishVO> getDishWithFlavorListByCategoryId(Long id) {
        String json = (String) redisTemplate.opsForValue().get("category_" + id);
        //缓存有数据直接返回
        if (json != null && json.length() > 0) return JSON.parseArray(json, DishVO.class);
        //没有缓存查数据库
        List<DishVO> list = baseMapper.getDishWithFlavorListByCategoryId(id, StatusConstant.ENABLE);
        //放缓存
        redisTemplate.opsForValue().set("category_" + id, JSON.toJSONString(list));
        return list;
    }

    @Transactional
    @Override
    public void changeStatus(Integer status, Long id) {
        //菜品停售，则包含菜品的套餐同时停售

        //更新菜品状态
        baseMapper.updateStatus(status, id);

        //如果是启用，将不涉及套餐的状态变更
        if (status == StatusConstant.ENABLE) return;

        //是禁用菜品，查询是否有关联的套餐
        List<SetmealDish> setmealDishList = setmealDishMapper.selectByDishId(id);
        if (setmealDishList == null || setmealDishList.size() == 0) return;

        //凡是关联此菜品的套餐需修改
        List<Long> setmealIds = setmealDishList.stream().map(SetmealDish::getSetmealId).collect(Collectors.toList());
        setmealMapper.updateStatusByIds(status, setmealIds);
    }

    private void delCache(String pattern){
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }
}
